home *** CD-ROM | disk | FTP | other *** search
-
- "Knowledge is Power, Power is Money"
-
- 3d Vectors Source
-
- by John McCarthy (with a little help from his mommy:eg food)
- 1316 Redwood Lane
- Pickering, Ontario, Canada
- L1X 1C5
-
- (905) 831-1944 (voice, always willing to talk, but do not call at 2am)
-
- Documentation is in no defined order. Sorry, I just sorta lumped my
- ideas together and ended up with this file.
-
- Routines support any x mode, - but page flipping is not allowed in
- resolutons which allow only 1 page - see "pages" constant.
-
- Full clipping is performed to user defind areas - see constants in
- equ.inc. They have been changed to memory locations for variable
- windowing or multiple screens. For windowing, the last z locations for
- that window must be remembered along with a slew of other locations, see
- vars.inc for that info. To change a window, save the lastz information,
- reset with old lastz information and then call set_clip to change the
- border clipping and screen center data.
-
- The theoretical screen is considered to be (x,y) with 0,0 being the
- center of the screen!. So -100,-100 is somewhere on the top left!
- actual screen goes from (0,0) to (320,200) - or whatever mode size you
- select. Matt Pritchard's routines (xmode.asm) assume 0,0 to be the top
- left of the screen while my routines (me = John = 3d.asm) consider the
- screen center to be the constants xcenter and ycenter.
-
- Visible space is -4628196 to +4628196 on all axis (approx). Object
- locations are 32 bit, vector routines are 16 bit, objects must be smaller
- than 16 bit but are visable within about a 32 bit range. (4 million, as
- it is now, is very very far). Since the camera is always at (0,0,0)
- (relative), objects with (relative) negative z values are not seen. This
- cuts the z space to 0 to 4mil. Visible space is always divided by 256 so
- decimals can be allowed in adding, and moving of objects. Visible space
- therefore, is actually from -1.024 billion to +1.024 billion with the
- lower byte having no effect on the location. Non-visible space is where
- objects can be but won't appear on screen. This space is a 256 *256*256
- cube. To racap: you have 32 bit x,y,z axis with a visual range of 28
- bits, where the lower 8 bits don't affect the location. (Lower 8 bits
- don't count because locations are shr'ed) i say that the visable space
- is "about" 4mil only because of the code in the make3d routine: this code
- multiplies by a constant and then performs divide by z distance. We
- cannot allow the multiply to overflow and therfore must truncate our
- maximum distance to prevent this. The constants for multiplication are
- the screen ratio constants and the calculation to test for an overflow is
- as such -2^32/2/256/(largest constant). The constant I have used is 464
- for the y ratio. I have used this because of my desire to use the
- 320x400 mode resolution. Therfore, 4.3gig/2/256/464 = about 4 million -
- our maximum visual distance. Like, trust me, you don't really need a
- larger universe. Fixing the make 3d routine wont allow you to see
- farther because then you would have to fix the rotate routine, etc, etc.
-
- When defining a location: ebx = x, ecx = y, ebp = z
- When defining a rotation: x = pitch, y = heading, z = yaw
- si refers to object number, di refers to time.
-
- Rotations occure in order:
- zobject,xobject,yobject,ycamera,xcamera,zcamera - rotations are
- compounded in matrix for faster computation.
-
- Vmatrix is the matrix for object rotation. Ematrix is the matrix for
- camera rotation. If you want know where a point in space will show up
- on the screen, load ebx, ecx, ebp with your x,y,z point, subtract camera
- location and call erotate (eye rotate). The point will be rotated
- according to current camera angles. Make sure that a call to setsincose
- has taken place to set the eye rotation matrix (ematrix).
-
- Polygon can handle any number of sides. To draw a triangle, make last
- point equal to first point, eg 1,4,5,1. Number of sides of a polygon is
- determined so that the polygon is not finished until the last side
- equals the first side: eg 1,7,6,14,13,4,2,1 would be a 7 sided polygon.
- The constant maxsurfaces determines the maximum number of surfaces an
- object can have. The constant maxpolys determines the maximum number of
- connections a surface can have.
-
- Sample shape data:
-
- thing dw 6 ; number of points
- dw 4 ; number of surfaces
- dw 25 dup (?) ; future use
-
- dw x,y,z ; point 0
- dw x,y,z ; point 1
- dw x,y,z
- ...
-
- dw command
- dw texture for side 1
- dw texture for side 2
- dw colour for side 1
- dw colour for side 2
- dw connection data eg (1,2,3,4,1)
- dw [?,?,?] [optional surface normal if command 128 used]
- dw more connection data...
- ...
-
- There are several commands one can use for each surface. Commands like
- steel texture, always visible, opposite colours, etc. View the objects
- include file to see what/how to use them.
-
- Bitmaps can be part of an object or be made as seperate objects. I will
- be using the bitmaps for things like explosions, smoke (from damaged
- planes/spaceships) and distant suns/solar system (U know, like in x-wing)
- set the values bitx and bity to the scaling to be used for each bitmap
- and set userotate to 2 as this is the command to define a bitmaped
- object. vxs and vys are the additional scaling used for individual
- objects (vxs+bitx = final scaling factor). When part of and object, use
- dw himap/lomap, point #, x scale, y scale. Remember, scaling is added to
- bitx and bity so objects have a base scale plus some individual scale.
-
- Complex objects don't cut it for speed! keep your objects simple and you
- can have more of them on screen at once! maximum speed is found with low
- resolutions. High resolutions with clipped borders also provide adaquate
- speed. A shallow but wide screen (small y, big x) provides better usage
- of cpu time than a tall and thin screen. One big object is faster to
- compute than many small objects (if same surface area) an object viewed
- from the side takes signifiganly less time to compute than if viewed
- from the top due to the shallow y, large x idea. Small option has been
- added for objects farther than smalldist distance. Object shapes have
- abcd prefixes. Therefore, as object gets farther from camera, less
- points/surface must be calculated. You must define four shapes for every
- shape. Hi-res shape is a, and lo-res shape is d.
- eg dd offset athing,offset bthing, offset cthing, offset dthing
-
- Surface data must be entered counter clockwize so side will be visible.
- Clockwize surfaces are visible from other side and will not be plotted
- (unless you use a surface command override, see objects.inc)
-
- An increase in screen objects increases cpu time. However, if you know
- that you will always have the screen filled (in the case of floors, and
- runways.) You can disable the clear_fill routine during those parts! if
- the screen will be covered with background walls and such, there is no
- purpose to call the clear routine to compute the next part! i have
- therefore added a flag for the clear_fill routine to use: when your
- animation comes to the part when your looking at the ground or walls (and
- there are NO empty spaces) toggle the flag to skip clear_fill and get
- more cpu time. This also works if you are approaching an object or
- large surface, since the new object will totaly cover the previous one.
- Another time trick is to have your main background object include the sky
- (or area to be cleared) as part of the object. If you are going to have
- walls that go halfway up the screen, have them go halfway with the
- regular walls and then make another surface that goes to the top of the
- screen (or above if you want to move around) with the colour 0. You can
- then deactivate the clear_fill routine and still have the animation
- appear as if the walls are completely seperate objects.
-
- Sorting routine for objects (as opposed to sides) uses last z value to
- re-sort for the next plot. If you plan on drawing static pictures you
- may want to call makobjs twice to: 1) draw and find zeds, sort, then 2)
- re-draw. This will be the only way (and easiest way) to plot an accurate
- picture of what we have. Don't worry about calling twice during
- animations as the first picture will be the only picture that is not
- sorted. During animations, all objects are sorted properly, based on
- previous z.
-
- Routines which are expected to be used in animations have been optimized
- but routines intended for use as background and title draw routines are
- not intended to be fast.
-
- PLEASE DOCUMENT YOUR CHANGES!!
-
- Newfollow routine does not handle object lock on well if object is
- accelerating. The routine calculates where the object will be in di
- frames and attempts to point the camera to it in di frames. However, if
- the object is accelerating, then the object will not be where it was
- expected to be at that time. So the camera must re-lock on to its
- target. This loop commences until the camera actually has locked on to
- the target object, from this point on, the camera will follow the object
- regardless of motion. The re-lock on sequence takes the last number of
- frames and divides it by two, so the re-lock on loop will move toward an
- accelerating object at an accelerating rate.
-
- General overview: locations are 32 bit -2.1Gig to +2.1Gig, angles are
- 16bit from 0-65535 degrees, 4 quadrants - 4096 entries each quadrant.
-
- Variables in vector routine are 16bit. cosine and sine list are words
- but get converted into doublewords when used.
-
- Some public routines: (not all, just some)
-
- arctan +/*% arctan(rise/run)=arctan(cx/ax). any quadrant, 16bit
- calc_angles +/*% calculate xy angles between object di and object si
- calc_middle +/*% calculate xy angles between object di and ebx,ecx,ebp
- checkfront +/*% test points (di,bp) (si,qds) (dx,qes) for clockwize
- clear_fill +/ clears write page using xupdate and yupdate variables
- compound + *% compounds angles of eye and angles of object into
- matrix
- cosine +/*% eax=cos(eax), 16bit input, 32bit output
- drawvect + draw list of vectors using points, sides and order
- erotate +/*% rotate for angles of eye, 32bit, uses ematrix
- fakedraw +/ draw line in firstbyte and lastbyte tables from xy1
- to xy2
- flip_page +/ flip between pages 0 and 1, wait for vertical sync
- get_displacement +/*% calculate difference between objects
- initfont # initialize font pointers
- initpages # initialize x-mode pages for flip_page to page 0
- loadpoints + *% load points into array, rotate and translate as we go
- loadsurfs + * load surfaces, check if visible as we go
- look_at_it +/* immediatly force eyeax, eyeay to look at object
- wherelook
- make1obj + * make object si
- make3d +/*% make bx,cx,bp into bx,cx 2d pair, 16bit
- makeobjs + make all objects then sorts based on last z location
- move_to # /* move object si to bx,cx,bp - time di frames
- newfollow # /* forces camera to follow object si, time to get there
- di
- poly_fill +/ uses oney,firstbyte and lastbyte to draw one surface
- point_it +/* point object si at object di
- point_dir +/* point object si in direction it is moving
- point_to +/* point object si at location ebx,ecx,ebp
- set_speed +/* calculate velocity based on angles
- point_time +/* point obj di to bx,cx,bp in di frames
- put_object +/* put object esi at location ebx,ecx,ebp
- re_sort + sorts objects based on "finalzed" values
- rotate +/*% rotate bx,cx,bp (x,y,z) through matrix vrotate, 16bit
- set_finall +/* calculate xsfinal for object (location)
- set_finala +/* calculate vxsfinal for object (angles)
- setmakeorder # resets order for makeobjs - for initialization
- setsincose +/ set sin and cos multipliers for eye rotations
- setupbase # set up object base pointers to shapes
- set_object_on /* turn object si on
- set_object_off /* opposite
- sine +/*% ax=sin(ax), 16bit input, 32bit output
- show_stars +/ display stars in background
- sort_list + sorts list of sides of polygon
- twist_si +/* set angular velocity based on ebx,ecx,ebp and di(time)
- updvectors +/ updates vector xyz's and angles
- where_si +/*% return location of where object will be in di frames
-
- Legend:
-
- # used for initialization of code or new scene
- + used regularly in animation loop
- / can be used by user outside of animation loop if needed
- * routine requires parameters passed in registers
- % routine exits with results in registers
- > routine wipes harddrive
-
- There are more routines at the end of 3d.asm for more general functions
- like find the camera displacement and finding rotational offsets between
- two objects. U figure them out - fairly self explanatory. Also check out
- poly.inc for more 3d functions and math.inc for general math functions.
-
- Divide overflows are generally caused by having an object behind the
- screen (or too close) and trying to calculate where it is on the screen.
- obviously this cannot be calculated (since is it off the screen) when
- this happens, ztruncate takes over in make3d routine. minz is set to
- more than the maximum distance any point on an object can be from its
- center of gravity. use ztruncate to truncate underflow of z to higher
- values to prevent overflows due to the object being too wide for the
- camera. increasing the zmin value prevents objects from coming too close
- to the screen. however, large objects (like battlecruisers, landing
- strips) must be allowed to come close, as the camera pans over the
- object, in this case, zmin is low but ztruncate takes over to "warp" the
- object to an appropiate on screen location. ztruncate used in make3d
- routine does not provide a true rendition of what a very-close object
- would look like but it's fast and simple. Generally, these values do not
- need to be changed unless close objects appear flat or objects disappear
- when they become too close. Objects disappear when they move to the
- other side of the camera.
-
- Drawvect routine has a seperate routine for drawing lines (as opposed to
- surfaces). The fake_line routine and poly_fill routine could do the job
- but they were too slow. The line was drawn twice then filled just like a
- polygon but now a seperate routine clipps and draws. If you need/want
- to use this line drawing routine it has been seperated from the
- draw_vect routine. I do not use the xmode line draw by Matt Pritchard
- as it does not allow for clipping.
-
- Sin and cosin tables - 90 degrees is now 16384, 180=32768...
-
- Move_si routine - to move an object around, load up ebx, ecx and ebp with
- the x,y,z locations of where you want the object to end up. Load di with
- the time you would like the object to take to get there. Load si with the
- object number you want to move and call move_si. The updvectors routine
- does the rest!
-
- To look at an object. either 1) put the object number in wherelook. or
- 2) load si with the object to look at, load di with the time to move the
- camera to the object, and call new_follow.
-
- Just think, only 7 months ago (march '93), i had trouble programming a
- batch file!
-
- Shape data can be almost as large as you need it 'till it crashes. try a cube
- 20000x20000x20000. calculations use 32 bit registers and can handle
- up to 16 bit locations. keeping the object size small will allow a larger
- visible space. but larger objects will allow you to get closer with more
- accuracy in the mathematics of rotations.
-
- List of command bits to date: (for object definitions)
-
- note: "visible" = "points appear counter-clockwise"
-
- texture definitions:
-
- 0 - normal surface, no features, constant colour.
- wavey - steel texture for surface 0 = none, colour offset determines
- screen offset for texture. eg 16+7 will use colour block 16-31
- but make the sine wave texture 14 (7*2) lines down. this is so
- all sine wave textures do not appear on the same line.
- windows and engines look good with this feature.
- shade - lambert shading bit, must have normal calculated or at least
- have free space for pre_cal_lambert to use:
- eg 128,16*1,1,2,3,1, ?,?,?<- these 3 words are surface normal!
- inverse - inversion bit for shading option. 0=normal shading, 1=inverse
- if option +4 is used, inversion automatically occures when
- other side is displayed.
- glow - =shade+inverse
- last - colour has same colour as previous surface (used when
- you want gourad shading, but want to avoid duplicate
- calculations - don't set gourad bit if this is what
- you use it for.) when this is used, the colour number
- determines the new colour block to use. the shading
- of this colour will be the same as the surface before
- it, but the colour block can be different.
-
- commands:
-
- point - defines a single point; must be repeated! eg dw 64,col,3,3
- line - if used, defines a line (must be set to define a true line)
- himap - if set, defines a bitmap,eg: point #, bitmap #, x scale,y scale
- lomap - uses 1/4 scaled bitmap (every 4'th pixel is sampled), fast
-
- iterate - generate iteration if side visible (iteration = sub-object)
-
- both - side is always visible no matter angle, skips counter-clowise test
- - "both sides have same texture"
- double - side is always visible but other side has high byte colour
- "double sided surface"
- note: if this is used, option "both" must not be used!!
- onscr - test if side is on screen - don't use if all points are
- outside clipping parameters.
- check - dont plot this side, just use as test points for visibility.
- this is mostly used with iterations.
-
- There are two kinds of bitmaps and points. Those which are inside objects
- and those which are seperate objects themselves. if userotate object command
- is set to himap/point,then the entire object is considered as a point
- or bitmap. But if userotate is not set this way, then a normal object is
- drawn and bitmaps then come from within the object definitions (below). this
- way, bitmaps and points can be either part of a larger object, or they are
- computed fast on their own. (eg explosions and bullets as seperate objects)
-
- Note: When writing surface descriptions, try to make the first value unique
- from any other first value. this way, the sort routine will give a more
- accurate sorting of sides. eg 1,3,6,1 2,4,1,2 rather than 1,3,6,1 1,2,4,1
-
- to recap:
-
- 0 = constant colour, only visible from counter-clockwise side
- wavey = sine texture
- shade = shading - requires 3 blank words for surface normal eg dw 0,0,0
- inverse = invert the shading direction, 0=normal, 1=sun is other way.
- last = use intensity from previous surface (not colour, only intensity)
- point = point
- line = line
- himap = bitmap (scalable, non-rotatable)
- lomap = bitmap (scalable, non-rotatable)
- iterate = generate iteration if side visible
- both = always visible
- double = always visible but other side has high byte colour,"double sided"
- onscr = plot side only if all the following points are on the screen
- check = dont plot side but use the following points as a test for visiblity
-
- What you can't mix on a single surface: "double" with "both"!!
-
- You do not have to define a point for the center of the object. the point
- 0 defines the center of the object. this is different from earlier versions
-
- Remember that negative y (-y) is up, +y is down. this is opposite from our
- regular grade 13 mathematics but it is consistant with the computers screen
- arrangement. if your objects look funny, make sure you have this correct.
-
- The shading for objects requires that 3 words be present after the side
- definition. These 3 words represent the surface normal to the side and can
- be either set by you (slow and tedious) by using the normal.bas program, or
- can be set up by the routine pre_cal_lambert. This routine scans the object
- to find surfaces that have the shading bit set (128). The surface normal
- will be calculated for that surface and stored in the 3 words set aside by
- you. If you remove the shading feature from a surface, make sure you remove
- the extra 3 words or it will screw up. But you knew that right. To use the
- routine pre_cal_lambert, load si with the object you wish to scan, and call.
- make sure objbase points to the offset of the object. si will be the object
- number, eg 0,1,2,3, not the offset. The offset will come from objbase.
-
- Each on-screen object can have it's own colour palette scheme by setting the
- palxref offsets to a cross reference palette. this uses the xlat command to
- take the objects colour, and xlat it into a new colour based on the xref
- table you provide. each object can have it own xref table. this way, many
- on-screen objects can use the same shape data while each is coloured with a
- different colour scheme (5 stuka airplanes all coloured differently, for
- example) You will find the palxref tables (for each object remember) in the
- file equ.inc. A routine set_xref_palette has been provided for you so you
- can set the xref offset (this routine is in poly.inc)
-
- To have a bitmap on the screen (scalable but non-rotatable) use option himap
- in either userotate or as an object command. Lomap uses the same bitmap
- method but only draws every 4'th pixel - good for explosions and smoke.
-